import axios from 'axios';
import { CancelSource } from '@/utils/request';
import dayjs from 'dayjs';
import CryptoJS from 'crypto-js';

// package localStorage
const KEY = 'kiple_value';
export const storage = {
  setItem: (key: string, value: any) => {
    const _key = CryptoJS.MD5(key).toString();
    const _value = CryptoJS.AES.encrypt(JSON.stringify(value), KEY).toString();
    localStorage.setItem(_key, _value);
  },
  getItem: (key: string) => {
    const _key = CryptoJS.MD5(key).toString();
    const localString = localStorage.getItem(_key);
    if (!localString) {
      return '';
    }
    const bytes = CryptoJS.AES.decrypt(localString, KEY);
    const originalText = bytes.toString(CryptoJS.enc.Utf8);

    return originalText ? JSON.parse(originalText) : '';
  },
  removeItem: (key: string) => {
    const _key = CryptoJS.MD5(key).toString();
    localStorage.removeItem(_key);
  },
};

export function delUserStorage() {
  storage.removeItem('account');
}

export const getQuery = (name: string) => {
  let result = location.search.split(`${name}=`)[1];
  result = result ? result.split('&')[0] : '';
  return result;
};

export const randomString = () => Math.ceil(1e6 * Math.random()).toString(36);

// cancel request
export const handleCancelRequest = () => {
  if (CancelSource.source?.cancel) {
    CancelSource.source?.cancel && CancelSource.source?.cancel();
    const CancelToken = axios.CancelToken;
    CancelSource.source = CancelToken.source();
  }
};

export const toThousands = (num: number | string, showDecimal = true) => {
  if (isNaN(Number(num))) {
    return '0.00';
  }
  const splitNum = Number(num).toFixed(2).split('.');
  const decimal = splitNum[1];
  const integer = splitNum[0].toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
  if (!showDecimal && decimal === '00') {
    return integer;
  }
  return `${integer}.${decimal}`;
};

export const getSixDecimals = (num: number) => Math.floor(num * 1000000) / 1000000;

// Calculate the amount, save two decimal places
export const getAmountTwoDecimals = (num: number, showComma = false) => {
  const realNum = Number(num.toFixed(12)).toFixed(2);
  if (showComma) {
    return toThousands(realNum, false);
  }
  return Number(realNum);
};

export const getTime = (text?: string) => dayjs(text).format('YYYY-MM-DD hh:mm A');
export const getCurTime = () => dayjs().format('YYYY-MM-DD HH:mm');

export const getTimeString = (text?: string) => (text ? dayjs(text).format('YYYY-MM-DD, hh:mm A') : dayjs().format('YYYY-MM-DD, hh:mm A'));

export const getDate = (text: string) => dayjs(text).format('YYYY-MM-DD');

export const specialTime = (times: string) => {
  const n = dayjs();
  const b = dayjs(times);
  const time =
    n.diff(b, 'second') > 60
      ? n.diff(b, 'minute') > 60
        ? n.diff(b, 'hour') > 24
          ? `${n.diff(b, 'day')} day`
          : `${n.diff(b, 'hour')} hour`
        : `${n.diff(b, 'minute')} minute`
      : `${n.diff(b, 'second') <= 0 ? 1 : n.diff(b, 'second')} second`;
  return time;
};

// used for get redux data.
export const getTrue = () => true;

export const getFiles = (files: { fileList: any[] }) => {
  if (!files) {
    return [];
  } else {
    return files.fileList?.map((item: any) => (item.originFileObj ? item.originFileObj : item)).filter((item) => item && item.uid);
  }
};

export const getPercent = (current: number, target: number) => {
  const total = current + target;
  let percentNumber = (current / total) * 100;
  if (percentNumber > 99 && percentNumber < 100) {
    percentNumber = 99;
  }
  if (percentNumber < 1 && percentNumber > 0) {
    percentNumber = 1;
  }
  return percentNumber.toFixed(0) + '%';
};

export const getScrollWidth = () => {
  const oDiv = document.createElement('div');
  oDiv.style.cssText = 'position:absolute; top:-9999px; width:100px; height:100px; overflow:hidden;';
  const noScroll = document.body.appendChild(oDiv).clientWidth;
  oDiv.style.overflowY = 'scroll';
  const scroll = oDiv.clientWidth;
  document.body.removeChild(oDiv);
  return noScroll - scroll;
};

class MathCompute {
  getDecimal(num: number) {
    let decimal = 0;
    try {
      decimal = Number(num).toString().split('.')[1].length;
    } catch (e) {
      decimal = 0;
    }
    return decimal;
  }
  getNumberAndDecimal(num1: number, num2: number) {
    const times = Math.pow(10, Math.max(this.getDecimal(num1), this.getDecimal(num2)));

    return {
      num1: parseInt((num1 * times + 0.5) as unknown as string),
      num2: parseInt((num2 * times + 0.5) as unknown as string),
      times,
    };
  }
  //  add
  add(originNum1: number, originNum2: number) {
    const { num1, num2, times } = this.getNumberAndDecimal(originNum1, originNum2);
    return (num1 + num2) / times;
  }
  //  minus
  sub(originNum1: number, originNum2: number) {
    const { num1, num2, times } = this.getNumberAndDecimal(originNum1, originNum2);
    return (num1 - num2) / times;
  }
  // multiplication
  mul(originNum1: number, originNum2: number) {
    originNum1 = Number(originNum1);
    originNum2 = Number(originNum2);
    const times = Math.pow(10, this.getDecimal(originNum1) + this.getDecimal(originNum2));
    return (Number(originNum1.toString().replace('.', '')) * Number(originNum2.toString().replace('.', ''))) / times;
  }
  // divide
  divided(originNum1: number, originNum2: number) {
    const { num1, num2 } = this.getNumberAndDecimal(originNum1, originNum2);
    return num1 / num2;
  }
}

export const computed = new MathCompute();
export const setFiledUndefined = (rowData: { [key: string]: any }, keys: string[]) => {
  keys.forEach((item) => {
    if (!rowData[item]) {
      rowData[item] = undefined;
    }
  });
};

export const isHasPhone = (mobile: string, area_code: string) => {
  if (area_code && mobile) {
    return `+${area_code} ${mobile} `;
  } else if (!area_code && mobile) {
    return `${mobile} `;
  } else {
    return 'N/A';
  }
};

export const debounce = (fn: Function, delay: number) => {
  let timer: any = null;
  return (...values: any) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(fn.bind(null, ...values), delay);
  };
};

// input 去空格
export const getValueFromNoSpace = (e: any) => {
  return e?.target?.value?.replace(/(^\s*)|(\s*$)/g, '');
}

// input 去空格+如果是空就变成undefined
export const getValueFromNoSpaceUndefined = (e: any) => {
  if (e?.target?.value === '') {
    return undefined
  }
  return e?.target?.value?.replace(/(^\s*)|(\s*$)/g, '');
}

export const getSuffixName = (file_path: string = '') => {
  if (!file_path) {
    return '';
  }
  return file_path.substring(file_path.lastIndexOf('.') + 1).toLowerCase();
}

// 金额格式化千分位
export const formatMoneyPrice = (value: number | string) => {
  // eslint-disable-next-line no-restricted-globals
  if (!value || isNaN(+value)) {
    return value
  }
  return value.toString().replace(/\B(?=(\d{3})+\b)/g, ',')
}

// 将金额（分）过滤显示为两位小数（元）， 如 0.00
export const formatMoney = (value: string) => {
  let patten = /^(-)?\d+(\.\d+)?$/;
  if (!(patten.exec(value) === null || value === "")) {
    let val = (+value) / 100;
    return formatMoneyPrice(Number(val).toFixed(2));
  }
  return value;
};

//支付方式
export const formatWay = (value: string) => {
  if (value === "Online") {
    return '线上支付'
  } else if (value === "Offline") {
    return '线下支付'
  } else if (value === "Pcline") {
    return 'PC端支付'
  }else if (value === "Offline_pos") {
    return '刷卡支付'
  }
  return value;
};

//分账状态
export const formatRouting = (value: number) => {
  if (value === 0) {
    return '未开始'
  } else if (value === 1) {
    return '分账中'
  } else if (value === 2) {
    return '成功'
  } else if (value === 3) {
    return '失败'
  }
  return value;
};

//分账账户类型 
export const formatdivideAccount = (value: string) => {
  if (value === 0) {
    return '门店'
  } else if (value === 1) {
    return '商户'
  } else if (value === 2) {
    return '渠道商'
  } else if (value === 3) {
    return '平台'
  }
  return value;
};


//判断退款结果
export const formatRefundStatus = (value: string) => {
  if (value === 'REFUND_APPLY') {
    return '申请退款'
  } else if (value === 'REFUND_SUCCESS') {
    return '退款成功'
  } else if (value === 'REFUND_FAIL') {
    return '退款失败'
  }
  return value;
};



//判断支付结果状态
export const formatPayState = (value: string) => {
  if (value === "CLOSED") {
    return '支付失败'
  } else if (value === "WAITING") {
    return '订单创建,等待支付'
  } else if (value === "PAY_START") {
    return '用户开始支付'
  } else if (value === "THIRD_PAYING") {
    return '三方支付进行中'
  } else if (value === "PAY_FAIL") {
    return '支付失败'
  } else if (value === "PAY_SUCCESS") {
    return '支付成功'
  } else if (value === "CANCEL_PAY") {
    return '用户取消支付'
  }
  return value;
};

//去除标签
export const formatContent = (value: string) => {
  const regex = /<[^>]+>/g;
  return value.replace(regex, '');
};

// 通过身份证号获取生日、年龄和性别
export const parseIDCard = (idCard: string) => {
  // 正则表达式匹配身份证号格式
  const reg = /^\d{17}[\dXx]$/;

  if (reg.test(idCard)) {
    // 提取出生日期
    const birthday = idCard.substring(6, 14);
    const year = birthday.substring(0, 4);
    const month = birthday.substring(4, 6);
    const day = birthday.substring(6, 8);

    // 计算年龄
    const currentYear = new Date().getFullYear();
    const age = currentYear - parseInt(year);

    // 提取性别
    const genderCode = parseInt(idCard.charAt(16));
    // 0-"女" 1-"男"
    const gender = genderCode % 2;

    return {
      birthday: year + "-" + month + "-" + day,
      age: age,
      gender: gender
    };
  }

  return null; // 身份证号格式不正确
}


/**
 * 导出 json 数据为 Excle 表格
 * @param {json} column 列
 * @param {json} headData 表头数据
 * @param {json} bodyData 表体数据
 * @param {string} sheetName 导出的文件名, 可选
 * 增加 \t 为了不让表格显示科学计数法或者其他格式
 */
export const jsonToExcel = (column: Array<any>, headData: Array<any>, bodyData: Array<any>, sheetName = 'Excle表格') => {
  // 组装表头
  let theadHtml = '';
  headData.map(list => {
    let th = ''
    list.map((item: { colspan: any; rowspan: any; text: string; }) => {
      th += `
        <th colspan="${item.colspan || 1}" rowspan="${item.rowspan || 1}">
          ${item.text + '\t'}
        </th>
      `;
    });
    theadHtml += `<tr>${th}</tr>`
  });

  // 组装表体
  let tbodyHtml = ''
  bodyData.map(item => {
    let td = ''
    column.map(n => {
      const val = item[n.key] || ''
      td += `<td style="text-align: center;">${val + '\t'}</td>`
    });
    tbodyHtml += `<tr>${td}</tr>`
  });

  // 将table添加到html中，在html中加入excel和sheet元素
  let template = `
    <html lang="" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel">
      <head>
        <title></title>
        <xml>
          <x:ExcelWorkbook>
            <x:ExcelWorksheets>
              <x:ExcelWorksheet>
              <x:Name>${sheetName}</x:Name>
              <x:WorksheetOptions>
                <x:DisplayGridlines/>
              </x:WorksheetOptions>
              </x:ExcelWorksheet>
            </x:ExcelWorksheets>
          </x:ExcelWorkbook>
        </xml>
      </head>
      <body>
        <table>
          <thead>${theadHtml}</thead>
          <tbody>${tbodyHtml}</tbody>
        </table>
      </body>
    </html>
  `;

  // encodeURIComponent 解决中文乱码
  const uri = 'data:text/xlsx;charset=utf-8,\ufeff' + encodeURIComponent(template);

  // 通过创建a标签实现
  const link = document.createElement("a");
  link.href = uri;
  link.download = `${sheetName + '.xlsx'}`; // 设置文件名
  link.click();
}

export const getYearList = () => {
  const list = []
  let year = new Date().getFullYear()
  const min = 2023
  while (year >= min) {
    list.push({
      label: year + '年',
      value: year
    })
    year = year - 1
  }
  return list
}

//格式化时间戳2024-08-08
export const formatTime = (val) => {
  if (!val) {
    return ""
  }
  const date = new Date(val);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始，需要加1
  const day = String(date.getDate()).padStart(2, '0');
  const formattedDate = `${year}-${month}-${day}` || '';
  return formattedDate
}

// 格式化时间戳为 2024-08-08 09:01:04
export const formatDetailedTime = (val) => {
  if (!val) {
    return ""
  }
  const date = new Date(val);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始，需要加1
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');
  const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` || '';
  return formattedDate;
}

//格式化时间2024-09-24T11:37:23.000+00:00 为标准时间
export const formatTimeNew = (isoString) => {
   if (!isoString) {
    return ""
  }
  const date = new Date(isoString);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');
    
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

//格式化时间2024-09-25T21:03:24 为标准时间
export const formatTimeNewTwo = (isoString) => {
   if (!isoString) {
    return ""
  }
  return isoString.replace('T', ' ');
}
